﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Newtonsoft.Json;
using Sparklings.Save;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Sparklings.Gui
{
#pragma warning disable 0649
    class LevelChoiceMapItem
    {
        public string LevelFile = "";
        public LevelMetaData metadata = null;
        public List<string> Required = new List<string>();
        public int X = 0;
        public int Y = 0;
        public bool HasRequirements(SavedData playerProgress)
        {
            if (playerProgress.NoLevelUnlockNeeded)
            {
                return true;// You can't stop the dev.
            }
            bool allGood = true;
            // Todo : change data structures to reduce algorithmic complexity.
            foreach (var requiredLevel in Required)
            {
                if (!playerProgress.LevelsFinished.Exists((e) => requiredLevel.Equals(e.Name, StringComparison.Ordinal)))
                {
                    allGood = false;
                }
            }
            return allGood;
        }
    }
    class LevelChoiceMapData
    {
        public string MapImagePath;
        public string MapLevelPath;
        public string MapLevelAllStarsPath;
        public List<LevelChoiceMapItem> Nodes;
    }
#pragma warning restore 0649
    class LevelChoiceMap : DraggableAndClickableControl
    {
        public LevelChoiceMap(GraphicsDevice graphicsDevice, SpriteFont font, Rectangle boundingBox, string fileToLoad, SavedData playerProgress)
            : base(boundingBox)
        {
            RootDir = new DirectoryInfo(new FileInfo(fileToLoad).DirectoryName);
            Data = JsonConvert.DeserializeObject<LevelChoiceMapData>(File.ReadAllText(fileToLoad), new JsonSerializerSettings() { MissingMemberHandling = MissingMemberHandling.Ignore });

            PlayerProgress = playerProgress;

            Font = font;
            BoundingBox = boundingBox;

            MapImage = Texture2D.FromStream(
                graphicsDevice,
                new FileStream(GetRelativeFile(Data.MapImagePath).FullName, FileMode.Open));

            DataDimensions = new Vector2(MapImage.Width, MapImage.Height);

            LevelEntryTexture = Texture2D.FromStream(
                graphicsDevice,
                new FileStream(GetRelativeFile(Data.MapLevelPath).FullName, FileMode.Open));
            if(Data.MapLevelAllStarsPath==null){
                LevelEntryAllStarsTexture = LevelEntryTexture;
            }else{
                LevelEntryAllStarsTexture = Texture2D.FromStream(
                    graphicsDevice,
                    new FileStream(GetRelativeFile(Data.MapLevelAllStarsPath).FullName, FileMode.Open));
            }
        }
        protected override void HandleClick(Vector2 clickPos)
        {
            LevelChoiceMapItem targeted = Data.Nodes.FirstOrDefault((item) => (new Vector2(item.X, item.Y) - clickPos).Length() < 30);
            if (targeted != null)
            {
                if (targeted.metadata == null)
                {
                    try
                    {
                        targeted.metadata = new LevelMetaData(GetRelativeFile(targeted.LevelFile).FullName);
                    }
                    catch
                    {
                        OnSelectNotExisting(targeted.LevelFile);
                        return;
                    }
                }
                if (targeted.HasRequirements(PlayerProgress))
                {
                    OnSelect(targeted.metadata);
                }
            }
        }
        public Texture2D GetDrawn(GraphicsDevice graphicsDevice)
        {
            using (var batch = new SpriteBatch(graphicsDevice))
            {
                var renderTarget = new RenderTarget2D(graphicsDevice, BoundingBox.Width, BoundingBox.Height);
                graphicsDevice.SetRenderTarget(renderTarget);
                graphicsDevice.Clear(Color.DarkBlue);
                batch.Begin();
                batch.Draw(MapImage, ViewOffset, Color.White);
                Vector2 levelEntryTextureOffset = new Vector2(LevelEntryTexture.Width, LevelEntryTexture.Height) / 2;
                foreach (var level in Data.Nodes)
                {
                    if (level.HasRequirements(PlayerProgress))
                    {
                        Texture2D levelTex;
                        if (PlayerProgress.LevelsFinished.Exists((l) => l.Name == level.LevelFile && l.StarsLeft == 0))
                        {
                            levelTex = LevelEntryAllStarsTexture;
                        }
                        else
                        {
                            levelTex = LevelEntryTexture;
                        }
                        batch.Draw(levelTex, new Vector2(level.X, level.Y) - levelEntryTextureOffset + ViewOffset, Color.White);
                    }
                }
                batch.End();
                graphicsDevice.SetRenderTarget(null);
                return renderTarget;
            }
        }
        protected FileInfo GetRelativeFile(string fileName)
        {
            FileInfo[] files = RootDir.GetFiles(fileName, SearchOption.AllDirectories);
            if (files.Length == 0)
            {
                throw new FileNotFoundException(fileName);
            }
            return RootDir.GetFiles(fileName, SearchOption.AllDirectories)[0];
        }
        private DirectoryInfo RootDir;
        public Action<LevelMetaData> OnSelect;
        public Action<string> OnSelectNotExisting;
        private SpriteFont Font;
        protected LevelChoiceMapData Data;
        protected Texture2D MapImage;
        protected Texture2D LevelEntryTexture;
        protected Texture2D LevelEntryAllStarsTexture;
        private Rectangle BoundingBox;
        protected SavedData PlayerProgress;
    }
}
